package wiiusej.apptest.statistics;

import java.io.IOException;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.Priority;
import org.apache.log4j.PropertyConfigurator;

import wiiusej.Wiimote;
import wiiusej.wiiusejevents.physicalevents.MotionSensingEvent;





public class PacketManager implements Callable {
	
	private static Logger fileLogger;
	private static Logger fileLoggerTime;
	private static Logger fileLoggerAcc;
	private static Logger fileLoggerDelay;
	
	
	private static Logger fileLoggerAccX;
	private static Logger fileLoggerAccY;
	private static Logger fileLoggerAccZ;
	
	
	private static final String fileURL = "src/test/java/wiiusej/apptest/statistics/logs/AccDataPaquets";
	private static final String fileURLTime = "src/test/java/wiiusej/apptest/statistics/logs/Time";
	private static final String fileURLAcc = "src/test/java/wiiusej/apptest/statistics/logs/Acceleration";
	private static final String fileURLDelay = "src/test/java/wiiusej/apptest/statistics/delay/logs/Api_to_Acc";
	
	
	
	private static final String fileURLAccX = 
		"src/test/java/wiiusej/apptest/statistics/logs/AccelerationX";
	
	private static final String fileURLAccY = 
		"src/test/java/wiiusej/apptest/statistics/logs/AccelerationY";
	
	private static final String fileURLAccZ = 
		"src/test/java/wiiusej/apptest/statistics/logs/AccelerationZ";
	
	
	private final MotionSensingEvent incomingEvent;
		
		
	Vector<AccelerationPaquet> myEventVector 
		= new Vector<AccelerationPaquet>();
	
	private PacketWraped myPackets; 
	
	
	private ArrayList<Integer> paquetsPerPeriod 
		= new ArrayList<Integer>();		
	
	
	private final int NANOS_FACTOR = 1000000;
	private final int SECOND_MILLIS = 1000;
	private final int NUMBER_OF_SLOTS = 4;
	private int timePerSlot;
	
	
	private AccelerationPaquet temporal;
	
	public PacketManager(MotionSensingEvent event, 
			Long id, Long random, PacketWraped myPackets){		
		
		this.incomingEvent = event;
		//this.myEventVector = (Vector<AccelerationPaquet>) myPackets.getPackets().clone();		
		this.myPackets = myPackets;
		this.temporal = myPackets.getTemporal();
		this.myEventVector = myPackets.getMyEventVector().getPackets();
			
		this.timePerSlot = SECOND_MILLIS/NUMBER_OF_SLOTS;
			
		wakeUpLogStats(id, random);
		
		
	}

	
	private void wakeUpLogStats(long id, long random) {
		
		PropertyConfigurator.configure("log4j.properties");	
		
		fileLoggerAccX = Logger.getLogger("statisticsAccX");	
		fileLoggerAccY = Logger.getLogger("statisticsAccY");
		fileLoggerAccZ = Logger.getLogger("statisticsAccZ");
		
		PatternLayout pattern1 = 
			new PatternLayout("%m%n");	
		
		try{
			
			FileAppender fileappendAccX=new FileAppender(pattern1,fileURLAccX + "_" + id + 
					"_" + random + ".log");
			
			fileappendAccX.setThreshold(Priority.DEBUG);			
			fileLoggerAccX.addAppender(fileappendAccX);
			

			FileAppender fileappendAccY=new FileAppender(pattern1,fileURLAccY + "_" + id + 
					"_" + random + ".log");
			fileappendAccY.setThreshold(Priority.DEBUG);			
			fileLoggerAccY.addAppender(fileappendAccY);
			

			FileAppender fileappendAccZ=new FileAppender(pattern1,fileURLAccZ + "_" + id + 
					"_" + random + ".log");
			fileappendAccZ.setThreshold(Priority.DEBUG);			
			fileLoggerAccZ.addAppender(fileappendAccZ);
			
		}catch(Exception e){
			e.printStackTrace();
		}
		
		fileLogger = Logger.getLogger("statistics");
		fileLoggerTime = Logger.getLogger("statisticsTime");
		fileLoggerAcc = Logger.getLogger("statisticsAcc");	
		fileLoggerDelay = Logger.getLogger("delayApiToAcc");
		
		
		PatternLayout pattern = 
			new PatternLayout("%m%n");		
		
		try {		
			//Creating a file for every connected wiimote
			FileAppender fileappend=new FileAppender(pattern,fileURL + "_" + id + ".log");
			fileappend.setThreshold(Priority.DEBUG);			
			fileLogger.addAppender(fileappend);
			
			FileAppender fileappendTime=new FileAppender(pattern,fileURLTime + "_" + id + 
					"_" + random + ".log");
			
			fileappendTime.setThreshold(Priority.DEBUG);			
			fileLoggerTime.addAppender(fileappendTime);
			
			FileAppender fileappendAcc=new FileAppender(pattern,fileURLAcc + "_" + id + ".log");
			fileappendAcc.setThreshold(Priority.DEBUG);			
			fileLoggerAcc.addAppender(fileappendAcc);			

			
			FileAppender fileappendDelay=new FileAppender(pattern,fileURLDelay + "_" + id + ".log");
			fileappendDelay.setThreshold(Priority.DEBUG);			
			fileLoggerDelay.addAppender(fileappendDelay);			
			
			
			
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}


	@Override
	public PacketWraped call() throws Exception {	
		
		takeStats();
		
		SimpleDateFormat tsFormat = new SimpleDateFormat("mm:ss:SS");
		
		Timestamp packetTime = incomingEvent.getTime();		
		Timestamp now = new Timestamp(System.currentTimeMillis());
		
		long motionPacketDelay = now.getTime() - packetTime.getTime();
		fileLoggerDelay.info(motionPacketDelay);
		fileLoggerTime.info(tsFormat.format(now));
		
		
		int accX = incomingEvent.getRawAcceleration().getX();
		int accY = incomingEvent.getRawAcceleration().getY();
		int accZ = incomingEvent.getRawAcceleration().getZ();
		
		fileLogger.info("Incoming EventTime: " + tsFormat.format(packetTime) + 
				" RealTime: " + tsFormat.format(now));
		
		
		if(myEventVector.isEmpty() && temporal.getTime() == null){
			
			fileLogger.info("Event Vector EMPTY");			
			
			temporal = new AccelerationPaquet(incomingEvent.getTime());
			setElementTime(temporal, tsFormat);
			
			temporal.uploadCounter();			
			addAccelerations(temporal, accX, accY, accZ);			
			myPackets.setTemporal(temporal);
			
			fileLogger.info("Creating temporal: " + myPackets.getTemporal().getCounter() + 
					" Time: " + tsFormat.format(myPackets.getTemporal().getTime()));
			
			fileLogger.info("");
			return myPackets;
			
		}else{					
			
			temporal = myPackets.getTemporal();		
			
			fileLogger.info("EventVector: " + myEventVector.size() + 
					" Temporal: " + tsFormat.format(myPackets.getTemporal().getTime()));
			
			
			int minuteRest = packetTime.getMinutes() - temporal.getTime().getMinutes();
			int secondRest = packetTime.getSeconds() - temporal.getTime().getSeconds();
			
			//MOD feedbacktime: 500 ms			
			//boolean samePeriod = sameHalfPeriod(packetTime);			
			
			boolean samePeriod = sameTimeSlot(tsFormat);
			
			fileLogger.info("MinuteRest: " + minuteRest + " SecondRest: " + secondRest + 
					" Same Period: " + samePeriod);
			
			if((secondRest==0) && (minuteRest==0) && samePeriod){				
				//wait until insert the new element
				temporal.uploadCounter();
				addAccelerations(temporal, accX, accY, accZ);
				myPackets.setTemporal(temporal);
				
				fileLogger.info("Same Period: " + temporal.getTime() + 
						" IncomingEvent: " + tsFormat.format(packetTime));
				
				fileLogger.info("Uploading Temporal Time: " + tsFormat.format(myPackets.getTemporal().getTime())
				+ " Counter: " + myPackets.getTemporal().getCounter());
				
			}else{
				//here we have to make the insertion
				//temporal = new AccelerationPaquet(incomingEvent.getTime());
				myEventVector.add(temporal);
				
				fileLogger.info("Adding Temporal To EventVector - Temporal:" 
						+ tsFormat.format(myPackets.getTemporal().getTime())
						+ " Counter: " + myPackets.getTemporal().getCounter());
				
				temporal = new AccelerationPaquet(incomingEvent.getTime());
				setElementTime(temporal, tsFormat);
				addAccelerations(temporal, accX, accY, accZ);
				temporal.uploadCounter();
				myPackets.setTemporal(temporal);
				
				fileLogger.info("New Temporal Packet: " + tsFormat.format(myPackets.getTemporal().getTime()));
			}
			
			fileLogger.info("");
			
			return myPackets;
		}
	
	
			
			
		
		
	}
	
	private void takeStats(){		
		SimpleDateFormat tsFormat = new SimpleDateFormat("mm:ss:SS");
		Timestamp now = incomingEvent.getTime();
		fileLoggerAccX.info(incomingEvent.getRawAcceleration().getX());
		fileLoggerAccY.info(incomingEvent.getRawAcceleration().getY());	
		fileLoggerAccZ.info(incomingEvent.getRawAcceleration().getZ());		
	}
	
	private void setElementTime(AccelerationPaquet packet, SimpleDateFormat tsFormat){
		
		int incomingPacketSlot = (int) (incomingEvent.getTime().getNanos() / (timePerSlot*NANOS_FACTOR));
		fileLogger.info("$$$ FINAL TIME PACKET: " + timePerSlot * incomingPacketSlot + 
				" Timeslot: " + incomingPacketSlot);
				
		packet.getTime().setNanos(timePerSlot * incomingPacketSlot * NANOS_FACTOR);
		fileLogger.info("*** Set Time: " + tsFormat.format(packet.getTime()));	
		
		
	}
	
	
	private boolean sameTimeSlot(SimpleDateFormat tsFormat) {		
		
		int incomingPacketSlot = (int) (incomingEvent.getTime().getNanos() / (timePerSlot* NANOS_FACTOR));
		int temporalPacketSlot = (int) (temporal.getTime().getNanos() / (timePerSlot*NANOS_FACTOR));
		
		fileLogger.info("***Incoming packet Time: " + tsFormat.format(incomingEvent.getTime()) + 
				" TimeSlot: " + incomingPacketSlot);

		fileLogger.info("***Last packet Time: " + tsFormat.format(temporal.getTime()) + 
				" TimeSlot: " + temporalPacketSlot);
		
		
		
		if(incomingPacketSlot == temporalPacketSlot){
			return true;		
		}		
		return false;
	}
	
	
	private void addAccelerations(AccelerationPaquet newPaquet, int accX, int accY, int accZ){
		newPaquet.addAccX(accX);
		newPaquet.addAccY(accY);
		newPaquet.addAccZ(accZ);		
	}
	

	
}
